package roborally;

import static org.junit.Assert.*;

import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import roborally.PlaceableType;
import roborally.Commands.Move;
import roborally.Commands.Turn;
import roborally.Conditions.Can_hit_robot;
import roborally.Conditions.Energy_at_least;
import roborally.commandCombiners.If;
import roborally.model.Facade;

@SuppressWarnings("unchecked")
public class Testsuite {
	
	private static Robot energylessRobot;
	private static Robot energyfullRobot;
	
	@Before
	public void setUp() throws Exception {
		Board board = new Board(1000,2000);
		energylessRobot = new Robot(board, 5,5,0,1000,20000);
		energyfullRobot = new Robot(board, 5,5,0,20000,20000);
	}
	
	@Test
	public void testBoardConstructor(){
		Board board = energyfullRobot.getBoard();
		assert((board).isTerminated() != true);
		assert(board.getWidth() == 1000);
		assert(board.getHeight() == 2000);
	}
	
	@Test
	public void testBoardHasPlaceableAtPosition(){
		Board board = energyfullRobot.getBoard();
		assertTrue(board.hasPlaceableAtPosition(5, 5));
	}
	
	@Test
	public void testBoardGetAllObjectsByPosition(){
		Board board = energyfullRobot.getBoard();
		Set<Placeable> set = board.getAllObjectsByPosition(5, 5);
		assert(set != null);
//		System.out.println(energyfullRobot);
//		System.out.println(energylessRobot);
//		for(Placeable p:set){System.out.println(p);}
		assertEquals(2, set.size());
		assert(set.contains(energylessRobot));
	}
	
	@Test
	public void testBoardGetAllObjectsByType() {
		Board board = energyfullRobot.getBoard();
		Set<Placeable>	set = (Set<Placeable>) board.getAllObjectsByType(PlaceableType.ROBOT);
		assert(set != null);
		assert(set.size()==2);
		assert(set.contains(energylessRobot));
		assert(set.contains(energyfullRobot));
	}
	
	@Test
	public void testBoardRemoveRobot() {
		Board board = energyfullRobot.getBoard();
		Set<Placeable>	set1 = (Set<Placeable>) board.getAllObjectsByType(PlaceableType.ROBOT);
		Set<Placeable>	set2 = (Set<Placeable>) board.getAllObjectsByPosition(5,5);
		board.removePlaceable(energylessRobot);
		assert(set1.size()==1);
		assert(set2.size()==1);
		assert(set1.contains(energyfullRobot));
		assert(set2.contains(energyfullRobot));
		assertFalse(set1.contains(energylessRobot));
		assertFalse(set1.contains(energylessRobot));
	}
	
	@Test
	public void testBoardRemoveRobotRemovesCoordinateFromSet(){
		Board board = energyfullRobot.getBoard();
		Set<Placeable>	set = (Set<Placeable>) board.getAllObjectsByPosition(5,5);
		board.removePlaceable(energyfullRobot);
		board.removePlaceable(energylessRobot);
		assert(set.isEmpty());
		assertFalse(board.hasPlaceableAtPosition(5, 5));
	}
	
	@Test
	public void testBoardRemoveRobotRemovesTypeFromSet() {
		Board board = energyfullRobot.getBoard();
		Set<Placeable>	set = (Set<Placeable>) board.getAllObjectsByType(PlaceableType.ROBOT);
		board.removePlaceable(energyfullRobot);
		board.removePlaceable(energylessRobot);
		assert(set.isEmpty());
	}
	
	@Test
	public void testNodeGetPath(){
		Node n1 = Node.getNode(Coordinate.getCoordinate(0,0),(long) 0,(long) 0,(long) 0 ,null,Orientation.RIGHT);
		Node n2 = Node.getNode(Coordinate.getCoordinate(0,1),(long) 0,(long) 0,(long) 0 ,n1,Orientation.RIGHT);
		Node n3 = Node.getNode(Coordinate.getCoordinate(0,2),(long) 0,(long) 0,(long) 0 ,n2,Orientation.RIGHT);
		Node n4 = Node.getNode(Coordinate.getCoordinate(0,3),(long) 0,(long) 0,(long) 0 ,n3,Orientation.RIGHT);
		List<Node> pathList = n4.getPath();
		Collections.reverse(pathList);
		assert(pathList.size()==4);
	}
	
	@Test
	public void testMerge(){
		Board board = new Board(2000,2000);
		Board board2 = new Board(2000,2000);
		Robot r = new Robot(0,5000);
		r.putRobot(board2, 5, 5);
		Battery b = new Battery(2000,2000);
		b.putBattery(board2, 10, 10);
		Wall wall = new Wall();
		Wall wall2 = new Wall();
		wall.putWall(board, 0, 0);
		wall2.putWall(board2, 1, 1);
		assertTrue(board.hasWallAtPosition(0, 0));
		assertFalse(board.hasWallAtPosition(1, 1));
		assertTrue(board2.hasWallAtPosition(1, 1));
		assertFalse(board2.hasWallAtPosition(0, 0));
		board.merge(board2);
		assertTrue(board2.isTerminated());
		assertTrue(board.hasWallAtPosition(0, 0));
		assertTrue(board.hasWallAtPosition(1, 1));
		assertTrue(board.getAllObjectsOnThisBoard().contains(r));
		assertTrue(!board.getAllObjectsByPosition(5, 5).isEmpty());
		assertTrue(board.getAllObjectsOnThisBoard().contains(b));
		assertTrue(!board.getAllObjectsByPosition(10, 10).isEmpty());
	}
	
	@Test
	public void testupdateHashMapByPositionAfterMove(){
		Board board = new Board(2000,2000);
		Robot r = new Robot(0,5000);
		r.putRobot(board, 5, 5);
		r.move();
		assertTrue(board.getAllObjectsByPosition(5, 5).isEmpty());
		assertEquals(1,board.getAllObjectsByPosition(5, 4).size());
		assertTrue(board.getAllObjectsByPosition(5, 4).contains(r));
	}
	
	@Test
	public void testShootPlaceableAt(){
		Board board = new Board(2000,2000);
		Robot r = new Robot(0,5000);
		SurpriseBox s = new SurpriseBox(1500);
		RepairKit k = new RepairKit(1500,1500);
		Battery b = new Battery(1500,1500);
		r.putRobot(board, 5, 5);
		s.putSurpriseBox(board, 7, 7);
		k.putRepairKit(board, 10, 10);
		b.putBattery(board, 15, 15);
		board.shootPlaceableAt(5, 5);
		assertEquals(16000,r.getMaxEnergy().getNumeral(),0.1);
		board.shootPlaceableAt(7, 7);
		assertTrue(s.isTerminated());
		board.shootPlaceableAt(10, 10);
		assertEquals(2000,k.getEnergy().getNumeral(),0.1);
		board.shootPlaceableAt(15, 15);
		assertEquals(2000,b.getEnergy().getNumeral(),0.1);
	}

	@Test
	public void testIterator(){
		Board board = new Board(2000,2000);
		Robot r = new Robot(0,5000);
		SurpriseBox s = new SurpriseBox(1500);
		RepairKit k = new RepairKit(1500,1500);
		Battery b = new Battery(1500,1500);
		r.putRobot(board, 5, 5);
		s.putSurpriseBox(board, 7, 7);
		k.putRepairKit(board, 10, 10);
		b.putBattery(board, 15, 15);
		Iterator<Placeable> it = board.getElementsByCondition();
		assertTrue(it.hasNext());
		it.next();
		assertTrue(it.hasNext());
		it.next();
		assertTrue(it.hasNext());
		it.next();
		assertTrue(it.hasNext());
		it.next();
		assertFalse(it.hasNext());
		Iterator<Placeable> it2 = board.getElementsByCondition(1);
		assertTrue(it2.hasNext());
		it2.next();
		assertFalse(it.hasNext());
	}
	
	@Test
	public void testEmptyBoardIterator(){
		Board board = new Board(2000,2000);
		Iterator<Placeable> it = board.getElementsByCondition();
		assertFalse(it.hasNext());
	}
	
	@Test (expected = IllegalStateException.class)
	public void testIteratorThrowExecption() throws IllegalStateException{
		Board board = new Board(2000,2000);
		Iterator<Placeable> it = board.getElementsByCondition();
		assertFalse(it.hasNext());
		it.next();
	}
	
	@Test (expected = UnsupportedOperationException.class)
	public void testIteratorThrowExecption2() throws UnsupportedOperationException{
		Board board = new Board(2000,2000);
		Iterator<Placeable> it = board.getElementsByCondition();
		it.remove();
	}
	
	@Test
	public void testConditionBoardIterator(){
		Board board = new Board(2000,2000);
		Robot r = new Robot(0,5000);
		SurpriseBox s = new SurpriseBox(1500);
		RepairKit k = new RepairKit(1500,1500);
		Battery b = new Battery(1500,1500);
		r.putRobot(board, 5, 5);
		s.putSurpriseBox(board, 7, 7);
		k.putRepairKit(board, 10, 10);
		b.putBattery(board, 15, 15);		
		Iterator<Placeable> it = board.getElementsByCondition(Energy_at_least.getInstance(1000));
		assertTrue(it.hasNext());
		it.next();
		assertTrue(it.hasNext());
		it.next();
		assertTrue(it.hasNext());
		it.next();
		assertFalse(it.hasNext());
	}
	
	@Test
	public void testConditionBoardIterator2(){
		Board board = new Board(2000,2000);
		Robot r = new Robot(0,5000);
		Robot t = new Robot(0,5000);
		SurpriseBox s = new SurpriseBox(1500);
		RepairKit k = new RepairKit(1500,1500);
		Battery b = new Battery(1500,1500);
		r.putRobot(board, 5, 5);
		t.putRobot(board, 5, 5);
		s.putSurpriseBox(board, 7, 7);
		k.putRepairKit(board, 10, 10);
		b.putBattery(board, 15, 15);		
		Iterator<Placeable> it = board.getElementsByCondition(Energy_at_least.getInstance(2000));
		assertTrue(it.hasNext());
		it.next();
		assertTrue(it.hasNext());
		it.next();
		assertFalse(it.hasNext());
	}
	
	@Test
	public void testConditionBoardIterator3(){
		Board board = new Board(2000,2000);
		Robot r = new Robot(0,5000);
		SurpriseBox s = new SurpriseBox(1500);
		RepairKit k = new RepairKit(1500,1500);
		Battery b = new Battery(1500,1500);
		r.putRobot(board, 5, 5);
		s.putSurpriseBox(board, 7, 7);
		k.putRepairKit(board, 10, 10);
		b.putBattery(board, 15, 15);		
		Iterator<Placeable> it = board.getElementsByCondition(Energy_at_least.getInstance(1000),2);
		assertTrue(it.hasNext());
		it.next();
		assertTrue(it.hasNext());
		it.next();
		assertFalse(it.hasNext());
	}
	
	@After
	public void clear(){
		Board board = energyfullRobot.getBoard();
		board.clearBoard();
	}
}
	
